#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/5/7 下午10:56
# @Author  : zhangzhen
# @Site    : 
# @File    : emoit.py
# @Software: PyCharm
import sys
import re
import random
import numpy as np
import matplotlib.pyplot as plt
from collections import defaultdict
from com.corpus.corpus import corpus
from matplotlib.font_manager import FontProperties

reload(sys)
sys.setdefaultencoding("utf-8")


class emoit():
    def __init__(self, emoit, type):
        """
        :param emoit: 
        :param type: 
        """
        self.__emoit = emoit
        self.__type = type
        self.__total = 7
        self.__dist = np.ones(7)  # 该表情在各类别的的分布情况

    def add_total(self):
        self.__total += 1

    def add_dist(self, type):
        self.__dist[type] += 1

    def set_total(self, total):
        self.__total = total

    def get_type(self):
        """返回表情类别"""
        return self.__type

    def get_prior(self):
        """根据标签的类别概率"""
        return self.__dist/self.__total


class emoit_utils():
    type = ["happiness", "like", "surprise", "sadness", "disgust", "anger", "fear"]
    emots = ["[haha][笑哈哈][耶][噢耶][太开心][哈哈][嘻嘻][乐乐][啦啦][呵呵][喜][微微笑][微笑][偷笑][呲牙][大笑][开心][调皮][握手][愉快][偷乐][喵喵][傻笑][憨笑][笑哈哈][吐舌头]",
             "[强][爱心][心][红心][爱][爱你][鲜花][给力][good][好喜欢][抱抱][握手][赞][威武][亲亲][加油啊][太阳][酷][鼓掌][干杯][奋斗][蛋糕][kiss][爱心传递][祈祷][喜欢][喜][心动][玫瑰][鼓掌][强壮][花朵][可爱][作揖][前进][礼花][爱情][约会][加油]][奋斗][OK][好棒][好][赞啊][鮮花][顶][胜利][拥抱][ok][花束][飞吻]",
             "[吃惊][惊讶][流汗][汗][晕][震惊][发呆][傻眼][哆啦A梦吃惊]",
             "[伤心][失望][悲催][呜呜][心碎][委屈][特委屈][衰][生病][困][可怜][泪][泪流满面][大哭][流泪][笑cry][悲伤][快哭了][BrokenHeart][感冒][难过][眼泪][淚][甜馨哭哭]",
             "[污][打脸][鄙视][害羞][脸红][鄙视][吐][doge][阴险][弱][最差][挖鼻屎][挖鼻][白眼][猪头][花心][做鬼脸][挤眼][浮云][来][讥笑][狗][调戏][书呆子][草泥马][花痴][色][色眯眯][我吐][烦躁][黑线][下][鬼脸二][撇嘴][二哈][坏笑][咒骂][勾引][闭嘴][doge][困][炸弹][贬低][哈欠][崩溃][糗大了][鼻涕][污]",
             "[右哼哼][左哼哼][哼][怒][怒骂][闭嘴][抓狂][愤怒][发怒][闪电][很生气][生气][刀][草泥马]",
             "[害怕][霹雳][紧张][吓][惊恐][恐怖][冰雹][抓狂][发抖][生病][骷髅][沙尘暴][幽灵][蛇]"]

    emoit_dict = dict()
    class_num = np.ones(7)
    total = 0
    @staticmethod
    def init_emoit():
        """初始化情感词典"""
        pattern = re.compile(r'\[(.*?)\]')
        for i, es in enumerate(emoit_utils.emots):
            matchs = pattern.findall(es)
            for m in matchs:
                e = '['+m+']'
                emoit_utils.emoit_dict[e] = emoit(e, emoit_utils.type[i])

    @staticmethod
    def train_emoit_emoit():

        # 初始化表情词典
        emoit_utils.init_emoit()

        # 获取各类语料 并统计表情的 先验概率
        for i in range(7):
            data = corpus('../../data/', str(i))
            emoit_corpus = data.get_emoit_corpus()
            emoit_utils.class_num[i] = len(emoit_corpus)
            emoit_utils.total += emoit_utils.class_num[i]
            for line in emoit_corpus:
                for e in line:
                    if e in emoit_utils.emoit_dict.keys():
                        # 获取值
                        emoit = emoit_utils.emoit_dict[e]
                        emoit.add_dist(i)  # 表情在各类别数量加1
                        emoit.add_total()  # 表情总数加1
                        # 设置值
                        emoit_utils.emoit_dict[e] = emoit

    @staticmethod
    def get_class_pro():
        """类别的先验概率"""
        return emoit_utils.class_num/emoit_utils.total

    @staticmethod
    def get_sent_pro(sent):
        res = np.zeros(7)
        if len(sent) > 0:
            for e in sent:
                if e in emoit_utils.emoit_dict.keys():
                    ee = emoit_utils.emoit_dict[e]
                    res += np.log(ee.get_prior())
            res += np.log(emoit_utils.get_class_pro())
        return res

    @staticmethod
    def test_type(sent):
        res = np.zeros(7)
        if len(sent) > 0:
            for e in sent:
                if e in emoit_utils.emoit_dict.keys():
                    ee = emoit_utils.emoit_dict[e]
                    res += np.log(ee.get_prior())
            res += np.log(emoit_utils.get_class_pro())
            return res.argmax()
        else:
            return None

def plot(precision,recall,types):

    x = [i for i, v in enumerate(types)]
    # 创建绘图对象，figsize参数可以指定绘图对象的宽度和高度，单位为英寸，一英寸=80px
    plt.figure(figsize=(8, 4))
    # 在当前绘图对象中画图（x轴,y轴,给所绘制的曲线的名字，画线颜色，画线宽度）
    # 宏平均(macro-average)和微平均(micro-average)
    #
    plt.plot(x, precision, 'ro-', label="$precision$", color="red", linewidth=2)
    plt.plot(x, recall, 'gv-', label="$recall$", color="green", linewidth=2)
    plt.plot(x, 2*precision*recall/(precision+recall), 'bs-', label="$F$", color="blue", linewidth=2)
    # X轴的文字
    plt.xticks(x, types, rotation=0)
    # Y轴的文字

    # 图表的标题
    plt.title(u'Classification Effect Based on Expression Feature')
    # Y轴的范围
    plt.xlim(0, len(types))
    plt.ylim(0.25, 1.0)
    # 显示图示
    plt.legend()
    plt.grid()
    # 显示图
    plt.show()


def get_test_corpus(num):
    """
    随机获取各类型的 num 条测试语料
    :param num: 
    :return: 
    """
    test_corpus = []
    for i in range(7):
        c = corpus('../../data/', str(i))
        # 表情语料
        if len(c.get_emoit_corpus()) > num:
            slice = random.sample(c.get_emoit_corpus(), num)
        else:
            slice = c.get_emoit_corpus()
        test_corpus.append(slice)
    return test_corpus

if __name__ == '__main__':

    emoit_utils.train_emoit_emoit()

    times = 100
    test_num = 100
    precision = np.zeros(7)
    recall = np.zeros(7)
    for time in range(times):
        acc = np.zeros(7)
        err = np.zeros(7)
        none = np.zeros(7)
        tc = get_test_corpus(test_num)
        for type, c in enumerate(tc):
            for sent in c:
                tt = emoit_utils.test_type(sent)
                if tt is not None:
                    if tt == type:
                        acc[tt] = acc[tt] + 1
                    else:
                        err[tt] = err[tt] + 1
                else:
                    none[type] = none[type] + 1

        precision += (acc)/(acc+err+none)
        recall += (acc)/100

    precision = precision/times
    recall = recall/times

    print "情感类别", emoit_utils.type
    print "准确率", precision
    print "召回率", recall
    print "F值", 2*precision*recall/(precision+recall)

    plot(precision, recall, emoit_utils.type)
    pass
